package com.boyinet.demo.pipelineleakage.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.alibaba.excel.EasyExcel;
import com.boyinet.demo.pipelineleakage.bean.primary.Sensor;
import com.boyinet.demo.pipelineleakage.bean.primary.Zero;
import com.boyinet.demo.pipelineleakage.excel.UploadDataListener;
import com.boyinet.demo.pipelineleakage.repository.primary.SensorRepository;
import com.boyinet.demo.pipelineleakage.repository.primary.ZeroRepository;
import com.boyinet.demo.pipelineleakage.util.LeakUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lengchunyun
 */
@Service
@Slf4j
public class SensorService {

    private final SensorRepository sensorRepository;

    private final ZeroRepository zeroRepository;

    public SensorService(SensorRepository sensorRepository, ZeroRepository zeroRepository) {
        this.sensorRepository = sensorRepository;
        this.zeroRepository = zeroRepository;
    }


    public void readFileAndSave(String fileName, Long pipeLineId) {
        EasyExcel.read(fileName, Sensor.class,
                new UploadDataListener(sensorRepository, pipeLineId)).sheet().doRead();
        calcLandR(pipeLineId);
    }

    private void calcLandR(Long pipeLineId) {
        List<Sensor> sensors = sensorRepository.findSensorsByHeadEqualsAndPipelineIdEquals(-1L, pipeLineId);
        log.info("[calcLandR],sensors:{}", sensors);
        //去重所有头结点
        Set<Long> headSet = sensors.stream().map(Sensor::getId).collect(Collectors.toSet());
        List<Sensor> sensorByHeadIn = sensorRepository.findSensorByHeadIn(headSet);
        //映射头结点NO 和 信息
        Map<Long, Sensor> sensorMap = sensorByHeadIn.stream().collect(Collectors.toMap(Sensor::getId, i -> i));
        List<Sensor> result = new ArrayList<>();
        sensors.forEach(sensor -> {
            BigDecimal lastR = BigDecimal.ZERO;
            BigDecimal lastL = BigDecimal.ZERO;
            while (sensor.getNext() != null) {
                Sensor next = sensorMap.get(sensor.getNext());
                next.setCalcL(sensor.getCalcL().add(next.getL()));
                next.setCalcR(LeakUtil.calcR(lastR, lastL, next.getR(), next.getCalcL()));
                if (next.getType() == 3) {
                    lastL = next.getCalcL();
                    lastR = next.getCalcR();
                } else {
                    lastL = BigDecimal.ZERO;
                    lastR = BigDecimal.ZERO;
                }
                result.add(next);
                sensor = next;
            }
        });
        sensorRepository.saveAll(result);
    }

    public List<Sensor> batchListByIds(List<Long> ids) {
        return sensorRepository.findSensorsByPipelineIdIn(ids);
    }

    public void deleteById(Long no) {
        log.info("[Sensor Delete]:{}", no);
        Optional<Sensor> sensor = sensorRepository.findById(no);
        sensor.ifPresent(s -> {
            boolean isHead;
            List<Sensor> sensors;
            switch (s.getType()) {
                case 0:
                case 4:
                    sensors = sensorRepository.findSensorByHeadIn(Collections.singleton(s.getId()));
                    isHead = true;
                    break;
                default:
                    sensors = sensorRepository.findSensorByHeadIn(Collections.singleton(s.getHead()));
                    isHead = false;
                    break;
            }
            sensors.forEach(sen -> {
                //为后继
                if ((no).equals(sen.getPre())) {
                    if (isHead) {
                        sen.setL(BigDecimal.ZERO);
                        sen.setCalcL(BigDecimal.ZERO);
                        sen.setType(s.getType());
                        sen.setHead(s.getHead());
                    }
                    sen.setPre(s.getPre());
                } else if ((no).equals(sen.getNext())) {
                    sen.setNext(s.getNext());
                }
            });
            if (isHead) {
                Long newHead = s.getNext();
                sensors.stream().filter(sen -> sen.getHead() != -1).forEach(sen -> sen.setHead(newHead));
                List<Zero> zeros = zeroRepository.findZerosByTargetEquals(s.getId());
                zeros.stream().filter(z -> (newHead).equals(z.getNo())).findFirst().ifPresent(stand -> {
                    zeros.forEach(zero -> {
                        zero.setTarget(stand.getNo());
                        zero.setDiffValue(zero.getDiffValue().subtract(stand.getDiffValue()));
                    });
                    zeroRepository.saveAll(zeros);
                });
            }
            sensorRepository.saveAll(sensors);
            sensorRepository.deleteById(no);
            calcLandR(s.getPipelineId());
        });
    }

    /**
     * 只允许更新k系数
     *
     * @param sensor
     */
    public void updateById(Sensor sensor) {
        sensorRepository.findById(sensor.getId()).ifPresent(old -> {
            BeanUtil.copyProperties(sensor, old, CopyOptions.create(Sensor.class, true));
            old.setK(sensor.getK());
            sensorRepository.save(old);
        });
    }

    public List<Sensor> findByPid(Long id) {
        return sensorRepository.findSensorsByPipelineIdEquals(id);
    }

    public void saveAll(List<Sensor> sensors) {
        sensorRepository.saveAll(sensors);
    }

    public void deleteByPipeLineId(Long id) {
        List<Sensor> sensors = this.findByPid(id);
        sensorRepository.deleteAll(sensors);
        List<Long> ids = sensors.stream().map(Sensor::getId).collect(Collectors.toList());
        List<Zero> zeros = zeroRepository.findZerosByNoIn(ids);
        zeroRepository.deleteAll(zeros);
    }
}
